package com.car.loan.framework.web.exception;

import com.car.loan.common.constant.HttpStatus;
import com.car.loan.common.exception.BaseException;
import com.car.loan.common.exception.CustomException;
import com.car.loan.common.exception.DemoModeException;
import com.car.loan.common.exception.loan.LoanParameterException;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.validation.ValidationException;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.RedisConnectionFailureException;
import org.springframework.data.redis.RedisSystemException;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.AccountExpiredException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.servlet.NoHandlerFoundException;
import com.car.loan.common.utils.StringUtils;
import com.car.loan.framework.web.domain.AjaxResult;

/**
 * 全局异常处理器
 *
 * @author ruoyi
 */
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    /**
     * 基础异常
     */
    @ExceptionHandler(BaseException.class)
    public AjaxResult baseException(BaseException e) {
        return AjaxResult.error(e.getMessage());
    }

    /**
     * 业务异常
     */
    @ExceptionHandler(CustomException.class)
    public AjaxResult businessException(CustomException e) {
        if (StringUtils.isNull(e.getCode())) {
            return AjaxResult.error(e.getMessage());
        }
        return AjaxResult.error(e.getCode(), e.getMessage());
    }

    @ExceptionHandler(NoHandlerFoundException.class)
    public AjaxResult handlerNoFoundException(Exception e) {
        log.error(e.getMessage(), e);
        return AjaxResult.error(HttpStatus.NOT_FOUND, "路径不存在，请检查路径是否正确");
    }

    @ExceptionHandler(AccessDeniedException.class)
    public AjaxResult handleAuthorizationException(AccessDeniedException e) {
        return AjaxResult.error(HttpStatus.FORBIDDEN, "没有权限，请联系管理员授权");
    }

    @ExceptionHandler(AccountExpiredException.class)
    public AjaxResult handleAccountExpiredException(AccountExpiredException e) {
        return AjaxResult.error(e.getMessage());
    }

    @ExceptionHandler(UsernameNotFoundException.class)
    public AjaxResult handleUsernameNotFoundException(UsernameNotFoundException e) {
        return AjaxResult.error(e.getMessage());
    }

    @ExceptionHandler(Exception.class)
    public AjaxResult handleException(Exception e) {
        log.error(e.getMessage(), e);
        return AjaxResult.error(e.getMessage());
    }


    @ExceptionHandler(value = RedisConnectionFailureException.class)
    @ResponseBody
    public AjaxResult handlerRedisConnectionFailureException(RedisConnectionFailureException e) {
        return AjaxResult.error("缓存连接超时，请重试");
    }

    @ExceptionHandler(value = RedisSystemException.class)
    @ResponseBody
    public AjaxResult handlerRedisSystemException(
        RedisSystemException e) {
        return AjaxResult.error("缓存连接超时，请重试");
    }

    @ExceptionHandler(value = MissingServletRequestParameterException.class)
    @ResponseBody
    public AjaxResult handlerMissingServletRequestParameterException(
        MissingServletRequestParameterException e) {
        return AjaxResult.error(e.getMessage());
    }

    /**
     * 验证异常
     */
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    @ResponseBody
    public AjaxResult handleMethodArgumentNotValidException(HttpServletRequest req,
        MethodArgumentNotValidException e) throws MethodArgumentNotValidException {
        BindingResult bindingResult = e.getBindingResult();
        StringBuilder errorMesssage = new StringBuilder("参数格式错误：");

        for (FieldError fieldError : bindingResult.getFieldErrors()) {
            errorMesssage.append(fieldError.getField()).append(fieldError.getDefaultMessage())
                .append(";");
        }
        return AjaxResult.error(errorMesssage.toString());
    }

    @ExceptionHandler(ValidationException.class)
    @ResponseBody
    public AjaxResult handlerUnexpectedTypeException(ValidationException e) {
        return AjaxResult.error(e.getMessage());
    }

    @ExceptionHandler(BindException.class)
    @ResponseBody
    public AjaxResult handlerBindException(BindException e) {
        List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
        StringBuilder sb = new StringBuilder();
        fieldErrors.forEach(fieldError -> {
            sb.append(fieldError.getField()).append("=[").append(fieldError.getDefaultMessage())
                .append("];");

        });
        return AjaxResult.error(sb.toString());
    }


    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    @ResponseBody
    public AjaxResult handMethodArgumentTypeMismatchException(
        MethodArgumentTypeMismatchException e) {
        return AjaxResult.error(e.getMessage());
    }

    @ExceptionHandler({LoanParameterException.class})
    @ResponseBody
    public AjaxResult handleException(LoanParameterException e) {
        return AjaxResult.error(e.getMessage());
    }


    /**
     * 请求方式不支持
     */
    @ExceptionHandler({HttpRequestMethodNotSupportedException.class})
    @ResponseBody
    public AjaxResult handleException(HttpRequestMethodNotSupportedException e) {
        return AjaxResult.error("不支持' " + e.getMethod() + "'请求");
    }

    /**
     * 演示模式异常
     */
    @ExceptionHandler(DemoModeException.class)
    public AjaxResult demoModeException(DemoModeException e) {
        return AjaxResult.error("演示模式，不允许操作");
    }
}
